package com.newlink.building.common_base.base

import android.app.Activity
import android.app.Application
import android.content.Context
import android.os.Build
import android.os.Bundle
import android.util.Log
import com.alibaba.android.arouter.launcher.ARouter
import com.facebook.soloader.SoLoader
import com.smart.rinoiot.common_sdk.cache.SharedPreferenceUtil
import com.smart.rinoiot.common_sdk.listener.OnNeedLoginListener
import com.smart.rinoiot.common_sdk.manager.FunInitManager
import com.smart.rinoiot.common_sdk.manager.ListenerManager
import com.newlink.building.common_base.constant.Base_Constant
import com.newlink.building.common_base.event.MessageEvent
import com.newlink.building.common_base.event.TYPE_APP_BACKGROUND
import com.newlink.building.common_base.event.TYPE_APP_REORDER_GLOBALPOPOVER_TO_FRONT
import com.newlink.building.common_base.model.bean.DeviceData
import com.newlink.building.common_base.utils.NLog
import com.newlink.building.common_base.utils.GooglePlayUtil
import com.newlink.building.common_base.utils.Base_Preference
import com.newlink.building.common_base.utils.RandomUtils
import com.newlink.building.common_base.utils.ScreenAdapter
import com.newlink.building.obfuscation.Module_Obfuscation_ObfuscationHelper
import com.newlink.building.obfuscation.Module_Obfuscation_ObfuscationInvoker
import com.tencent.bugly.crashreport.CrashReport
import org.greenrobot.eventbus.EventBus
import kotlin.properties.Delegates


/**
 * Created by xiaodong on 2022/8/22.
 */
open class BaseApplication : com.smart.rinoiot.common_sdk.base.BaseApplication(),
    OnNeedLoginListener {

    val isDebug: Boolean = true

    var isAppForeground = false
        private set
    private val activeActivities = HashSet<Class<out Activity>>()
    private var globalPopoverActivityCalssName =
        "com.newlink.building.record.GlobalPopoverActivity"
    private var incomingCallActivityCalssName =
        "com.newlink.building.activities.call.IncomingCallActivity"

    companion object {
        var cacheDeviceDatas: MutableList<DeviceData> = mutableListOf()

//        private var mqttMsgIdArray: MutableSet<String> = mutableSetOf()

        var context: Context by Delegates.notNull()
            private set

        lateinit var instance: Application

//        var rinoManager: ConnectionController by Delegates.notNull()
//            private set

        //随机端口号(暂时禁用)
        val randomPort = RandomUtils.generateRandomPort()

        fun memoryCacheDeviceData(data: MutableList<DeviceData>) {
            // 缓存设备数据时的安全混淆
            Module_Obfuscation_ObfuscationHelper.beforeDatabaseOperation("CACHE_DEVICE", data.size.toString())
            Module_Obfuscation_ObfuscationInvoker.invokeSpecific(21, data.hashCode())

            NLog.d("memoryCacheDeviceData data = $data")
            this.cacheDeviceDatas = data
        }

        fun getDeviceDataByUsername(username: String?): DeviceData? {
            var deviceData: DeviceData? = null
            for (item in cacheDeviceDatas) {
                if (item.aid.toString() == username) {
                    deviceData = item
                    break
                }
            }
            return deviceData
        }

        fun getDeviceDataByMac(mac: String?): DeviceData? {
            var deviceData: DeviceData? = null
            for (item in cacheDeviceDatas) {
                if (item.mac == mac) {
                    deviceData = item
                    break
                }
            }
            return deviceData
        }

        //        fun saveMsgId(msgId: String) {
//            mqttMsgIdArray.add(msgId)
//        }
//
//        fun isUsedMsgId(msgId: String) :Boolean{
//            return mqttMsgIdArray.contains(msgId)
//        }
//
//        fun isNewMsgId(msgId: String) :Boolean{
//            return !mqttMsgIdArray.contains(msgId)
//        }
//
//        fun removeMsg(msgId: String) :Boolean {
//            return mqttMsgIdArray.remove(msgId)
//        }
//        fun getDTMFs(username: String?): MutableList<DoorData>? {
//            var doorDatas: MutableList<DoorData>? = mutableListOf()
//            for (item in cacheDeviceDatas) {
//                if (item.sip == username) {
//                    doorDatas = item.doors
//                    break
//                }
//            }
//            return doorDatas
//        }
        fun getCurrentLocale(): String {
            val locale = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                context.resources.configuration.locales.get(0);
            } else {
                context.resources.configuration.locale;
            }

            var localeStr = "${locale.language}-${locale.country}"

            //T90913 修改简体中文选择其他地区
            if (locale.toLanguageTag().contains("zh-Hans")) {
                localeStr = "zh-CN"
            }
            return localeStr
        }

        fun getCurrentLanguage(): String {
            val locale = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                context.resources.configuration.locales.get(0);
            } else {
                context.resources.configuration.locale;
            }
            val localeStr = locale.language
            return localeStr
        }

        fun getCurrentCountryLanguage(): String {
            val locale = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                context.resources.configuration.locales.get(0);
            } else {
                context.resources.configuration.locale;
            }
            val localeStr = "${locale.language}_${locale.country}"
            return localeStr
        }

    }

    override fun onCreate() {
        super.onCreate()
        // 应用启动时的核心混淆
        Module_Obfuscation_ObfuscationHelper.onMethodEnter("BaseApplication", "onCreate")
        Module_Obfuscation_ObfuscationInvoker.invokeRandom(System.currentTimeMillis())

        instance = this
        context = applicationContext
        initApiEnv()
        ScreenAdapter.setup(this)
        ScreenAdapter.register(
            this,
            Base_Constant.SCREEN_DESIGN_SIZE,
            ScreenAdapter.MATCH_BASE_WIDTH,
            ScreenAdapter.MATCH_UNIT_DP
        )
        registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks {
            private var activityReferences = 0
            private var isActivityChangingConfigurations = false

            override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
                activeActivities.add(activity.javaClass)
            }

            override fun onActivityStarted(activity: Activity) {
                if (++activityReferences == 1 && !isActivityChangingConfigurations) {
                    isAppForeground = true
                    EventBus.getDefault().post(MessageEvent(TYPE_APP_BACKGROUND, false))
                }
                if (activity.javaClass.name == incomingCallActivityCalssName) {
                    if (isActivityInStack(globalPopoverActivityCalssName)) {
                        EventBus.getDefault()
                            .post(MessageEvent(TYPE_APP_REORDER_GLOBALPOPOVER_TO_FRONT, true))
                    }
                }

//                navigateToGlobalPopoverActivityIfExists()
            }

            override fun onActivityResumed(activity: Activity) {}

            override fun onActivityPaused(activity: Activity) {}

            override fun onActivityStopped(activity: Activity) {
                isActivityChangingConfigurations = activity.isChangingConfigurations
                if (--activityReferences == 0 && !isActivityChangingConfigurations) {
                    isAppForeground = false
                    EventBus.getDefault().post(MessageEvent(TYPE_APP_BACKGROUND, true))
                }
            }

            override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}

            override fun onActivityDestroyed(activity: Activity) {
                activeActivities.remove(activity.javaClass)
            }
        })

        init()
        if (isDebug) {
            ARouter.openLog();     // Print log
            ARouter.openDebug();
        }
        ARouter.init(this)
        when (GooglePlayUtil.onCheckGooglePlayServices(this)) {
            true -> NLog.d("国外版本")

            false -> NLog.d("国内版本")
        }


        // 初始化 bugly
        CrashReport.initCrashReport(this, "fc555ec11f", true)
    }

    /**
     * rino init
     */
    override fun init() {
        FunInitManager.getInstance().init(this)
        SharedPreferenceUtil.getInstance().init(this)
        SoLoader.init(this, false)
        ListenerManager.getInstance().needLoginListener = this
    }

    //环境初始化,如果是自定义的url则赋值 - 模仿原项目neutral渠道配置
    fun initApiEnv() {
        // 从SharedPreferences读取用户保存的API环境URL，默认使用BASE_XLINK_URL
        val api_env_url: String by Base_Preference(Base_Constant.API_ENV_URL, Base_Constant.BASE_XLINK_URL)
        Base_Constant.BASE_URL = api_env_url

        Log.d("BaseApplication", "initApiEnv: 当前API环境URL = ${Base_Constant.BASE_URL}")

        // 注意：这里用户可以通过应用内的环境选择界面来切换到ApiEnv中定义的任意环境
        // 切换时会更新SharedPreferences中的API_ENV_URL值
    }

    fun getCurrentLocale2(): String {
        val locale = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            resources.configuration.locales.get(0);
        } else {
            resources.configuration.locale;
        }
        return locale.language
    }

    override fun tokenInvalid(p0: Boolean) {
        Log.e("fvl_dbg", "<jake> [Rino] ★★★ tokenInvalid : $p0")

    }

    override fun needLogin(p0: Boolean) {
        Log.e("fvl_dbg", "<jake> [Rino] ★★★ needLogin : $p0")
    }

    // 判断指定 Activity 是否在任务栈中
    fun isActivityInStack(activityClass: Class<out Activity>): Boolean {
        return activeActivities.contains(activityClass)
    }

    // 判断指定 Activity 是否在任务栈中
    fun isActivityInStack(activityName: String): Boolean {
        // 遍历 activeActivities 集合
        for (activityClass in activeActivities) {
            // 获取每个 Activity 类的全限定名并与传入的 activityName 比较
            if (activityClass.name == activityName) {
                return true
            }
        }
        return false
    }
}
